#pragma once

#include "../../inc/TopoDS/OMIT_MeshForwardDecl.h"

namespace OMIT_NAMESPACE
{
	template<typename Traits>
	class TMesh_H
    {
	public:
		using TV = MeshTraits_V<Traits>;
		using TE = MeshTraits_E<Traits>;
		using TF = MeshTraits_F<Traits>;
		using TH = MeshTraits_H<Traits>;

	public:
		TH* Next()			noexcept { return _next; }
		TH* Pair()			noexcept { return _pair; }
		TV* Origin()		noexcept { return _origin; }
		TE* Edge()			noexcept { return _edge; }
		TF* Face()			noexcept { return _face; }
		TV* End()			noexcept { return Next()->Origin(); }
		TH* Pre()			noexcept;
		TH* RotateNext()	noexcept { return Pair()->Next(); }
		TH* RotatePre()		noexcept { return Pre()->Pair(); }

		const TH* Next()		const noexcept { return const_cast<TH*>(PThis())->Next(); }
		const TH* Pair()		const noexcept { return const_cast<TH*>(PThis())->Pair(); }
		const TV* Origin()		const noexcept { return const_cast<TH*>(PThis())->Origin(); }
		const TE* Edge()		const noexcept { return const_cast<TH*>(PThis())->Edge(); }
		const TF* Polygon()		const noexcept { return const_cast<TH*>(PThis())->Face(); }
		const TV* End()			const noexcept { return const_cast<TH*>(PThis())->End(); }
		const TH* Pre()			const noexcept { return const_cast<TH*>(PThis())->Pre(); }
		const TH* RotateNext()	const noexcept { return const_cast<TH*>(PThis())->RotateNext(); }
		const TH* RotatePre()	const noexcept { return const_cast<TH*>(PThis())->RotatePre(); }

		void SetNext(TH* h)		noexcept { _next = h; }
		void SetPair(TH* h)		noexcept { _pair = h; }
		void SetOrigin(TV* v)	noexcept { _origin = v; }
		void SetEdge(TE* e)		noexcept { _edge = e; }
		void SetFace(TF* f)		noexcept { _face = f; }

		// next、pair、v 和 e 不能为空指针，f 可以是空指针
		void Init(TH* next, TH* pair, TV* v, TE* e, TF* f = nullptr) noexcept;

		void Reset() noexcept;

		// 半边在边界上，对应于关联的面为空指针
		bool IsOnBoundary() const noexcept { return !_face; }

		// 按照半边的后继方式访问左闭右开区间 [begin, end)
		// 如果 begin === end 表示形成了环路
		static H_NextView<false, Traits> NextBetween(TH* begin, TH* end) { return { begin, end }; }
		// 按照半边的后继方式访问左闭右开区间 [this, end)
		// 调用 NextBetween(this, end)
		H_NextView<false, Traits> NextTo(TH* end) { return NextBetween(PThis(), end); }
		// 按照半边的后继方式访问左闭右开区间 [this, this)
		// 访问从 this 开始到 this 的环路
		H_NextView<false, Traits> NextLoop() { return NextTo(PThis()); }

		// 同名函数的 const 版本
		// 按照半边的后继方式访问左闭右开区间 [begin, end)
		// 如果 begin === end 表示形成了环路
		static H_NextView<true, Traits> NextBetween(const TH* begin, const TH* end) { return { begin, end }; }
		// 同名函数的 const 版本
		// 按照半边的后继方式访问左闭右开区间 [this, end)
		// 调用 NextBetween(this, end)
		H_NextView<true, Traits> NextTo(const TH* end) const { return NextBetween(PThis(), end); }
		// 同名函数的 const 版本
		// 按照半边的后继方式访问左闭右开区间 [this, this)
		// 访问从 this 开始到 this 的环路
		H_NextView<true, Traits> NextLoop() const { return NextTo(PThis()); }

		// 按照半边的旋转后继方式访问左闭右开区间 [begin, end)
		// 如果 begin === end 表示遍历了 1—邻域
		static H_RotaView<false, Traits> RotateNextBetween(TH* begin, TH* end) { return { begin, end }; }
		// 按照半边的旋转后继方式访问左闭右开区间 [this, end)
		// 调用 NextBetween(this, end)
		H_RotaView<false, Traits> RotateNextTo(TH* end) { return RotateNextBetween(PThis(), end); }
		// 按照半边的旋转后继方式访问左闭右开区间 [this, this)
		// 访问从 this 开始到 this 的环路
		H_RotaView<false, Traits> RotateNextLoop() { return RotateNextTo(PThis()); }

		// 同名函数的 const 版本
		// 按照半边的旋转后继方式访问左闭右开区间 [begin, end)
		// 如果 begin === end 表示遍历了 1—邻域
		static H_RotaView<false, Traits> RotateNextBetween(const TH* begin, const TH* end) { return { begin, end }; }
		// 同名函数的 const 版本
		// 按照半边的旋转后继方式访问左闭右开区间 [this, end)
		// 调用 NextBetween(this, end)
		H_RotaView<false, Traits> RotateNextTo(const TH* end) const { return RotateNextBetween(PThis(), end); }
		// 同名函数的 const 版本
		// 按照半边的旋转后继方式访问左闭右开区间 [this, this)
		// 访问从 this 开始到 this 的环路
		H_RotaView<false, Traits> RotateNextLoop() const { return RotateNextTo(PThis()); }

		// 获得半边关联的面的边数
		std::size_t FaceDegree() const noexcept;

	private:
		friend TMesh<Traits>;
		friend TVert<Traits>;

		bool IsFree() const noexcept { return !_face; }
		static bool MakeAdjacent(TH* begin, TH* end);
		static TH* FindFreeIncident(TH* begin, TH* end);

		TH* PThis() noexcept { return static_cast<TH*>(this); }
		const TH* PThis() const noexcept { return static_cast<const TH*>(this); }

		TH* _next	{ nullptr };
		TH* _pair	{ nullptr };

		TV* _origin	{ nullptr };
		TE* _edge	{ nullptr };
		TF* _face	{ nullptr };
    };
}

#include "../../inc/TopoDS/OMIT_MeshHalfEdge.inl"